#include<fcntl.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<inttypes.h>
struct bitmap_header {
  uint8_t  magic_nr[2];
  uint32_t bmp_size;
  uint32_t unused;
  uint32_t offset_data;
  uint32_t header_size;
  uint32_t width;
  uint32_t height;
  uint32_t bitsandplanes;
  uint32_t compression;
  uint32_t data_size;
  uint32_t unused2[4];
}__attribute__((__packed__));

int main(int argc, char *argv[])
{
  int fpin,fpout,i,j;
  off_t res;
  off_t filesize;
  uint8_t *img_data;
  uint8_t *yuv_data;
  float y,cb,cr;
  uint8_t r,g,b;
  struct bitmap_header bmh;

  if(argc < 3)
  {
    printf("please use %s file.bmp file.yuv\n", argv[0]);
    return 1;
  }
  fpin = open(argv[1], O_RDONLY);
  if(fpin < 0)
  {
    printf("file %s could not be opened\n", argv[1]);
    return 2;
  }
  filesize = lseek(fpin, 0L, SEEK_END);
  if(filesize < 0)
  {
    perror("fseek1");
    return 3;
  }
  res = lseek(fpin, (off_t)0, SEEK_SET);
  if(res < 0)
  {
    perror("fseek2");
    return 4;
  }

  printf("inputfile has %0ld bytes\n", filesize);

  if(read(fpin, &bmh, sizeof(struct bitmap_header))<0)
  {
    perror("read bmh");
    return 5;
  }
  printf("bitmap widthxheight %dx%d\n",bmh.width,bmh.height);
  printf("bitmap colorsplanes %08x\n",bmh.bitsandplanes);

  if((bmh.width == 640)&&(bmh.height == 480)&&
     (bmh.bitsandplanes == 0x00180001))
  {
    printf("bitmap ok\n");
    img_data = malloc(921600);
    if(img_data == NULL)
    {
      perror("cannot malloc img_data");
      return 6;
    }
    if(read(fpin, img_data,921600)<0)
    {
      perror("read img_data");
      return 5;
    }
    //reverse image
    for(j=0;j<240;j++)
    {
      for(i=0;i<640;i++)
      {
        b = img_data[j*640*3+i*3];
        g = img_data[j*640*3+i*3+1];
        r = img_data[j*640*3+i*3+2];
        img_data[j*640*3+i*3]   = img_data[(479-j)*640*3+i*3];
        img_data[j*640*3+i*3+1] = img_data[(479-j)*640*3+i*3+1];
        img_data[j*640*3+i*3+2] = img_data[(479-j)*640*3+i*3+2];
        img_data[(479-j)*640*3+i*3]   = b;
        img_data[(479-j)*640*3+i*3+1] = g;
        img_data[(479-j)*640*3+i*3+2] = r;

        //printf("%02x%02x%02x,",img_data[j*640*3+i*3],img_data[j*640*3+i*3+1],img_data[j*640*3+i*3+2]);
      }
    }
    //bgr24 -> yuv444
    for(j=0;j<480;j++)
    {
      for(i=0;i<640;i++)
      {
        b = img_data[j*640*3+i*3];
        g = img_data[j*640*3+i*3+1];
        r = img_data[j*640*3+i*3+2];
        y=   0.299*r + 0.587*g +  0.114*b;
        cb= -0.169*r - 0.331*g +  0.499*b + 128;
        cr=  0.499*r - 0.418*g - 0.0813*b + 128;
        if(y>255)
          y = 255;
        if(y<0)
          y = 0;
        if(cb>255)
          cb = 255;
        if(cb<0)
          cb = 0;
        if(cr>255)
          cr = 255;
        if(cr<0)
          cr = 0;
        img_data[j*640*3+i*3]   = (uint8_t)cb;
        img_data[j*640*3+i*3+1] = (uint8_t)y;
        img_data[j*640*3+i*3+2] = (uint8_t)cr;
        
        //printf("%02x%02x%02x,",img_data[j*640*3+i*3],img_data[j*640*3+i*3+1],img_data[j*640*3+i*3+2]);
      }
      //printf("\n");
    }
    //write yuv444 ->yuv420p
    fpout = open(argv[2], O_CREAT|O_TRUNC|O_WRONLY,S_IRUSR|S_IWUSR);
    if(fpout < 0)
    {
      printf("file %s could not be opened\n", argv[2]);
      return 2;
    }
    yuv_data = malloc(307200+153600);
    if(yuv_data == NULL)
    {
      perror("cannot malloc yuv_data");
      return 6;
    }
    for(j=0;j<480;j++)
    {
      for(i=0;i<640;i++)
      {
        yuv_data[j*640+i] = img_data[j*640*3+i*3+1];
        if((i%2==0)&&(j%2==0))
        {
          yuv_data[307200+(j/2)*320+i/2] = img_data[j*640*3+i*3];
          yuv_data[307200+76800+(j/2)*320+i/2] = img_data[j*640*3+i*3+2];
        }
      }
    }
    if(write(fpout, yuv_data, (307200+153600))<0)
    {
      perror("write");
      return 5;
    }

  }
  close(fpin);
  close(fpout);
  return 0;
}
